
'use strict';

/**
	Part of Zombie Navigator
	Copyright © 2015  Zombie Navigator Developers
	
	@file
	@module
	@license AGPL-3.0+
*/


/*
	This is an internal module used inside the abstraction wrapper.
*/


/* Addon SDK dependencies */
// sdk/windows
const _sdkIsPrivate = require('sdk/private-browsing').isPrivate;


/* Used modules */
const _modContentScript = require('./content-script');
const _modURI = require('../uri');


/* Exported APIs */


/**
	Wrap an SDK Tab object
	@protected
*/
const createSDKTabWrapper = sdkTab => {
	let closed = false;
	const closeHandlers = new Set();
	
	try {
		sdkTab.once('close', sdkTab => {
			closed = true;
			for (let handler of closeHandlers) {
				handler();
			}
		});
	} catch (e) {}
	
	const wrapper = {
		__proto__: null
		,
		close () {
			return new Promise((resolve, reject) => {
				try {
					sdkTab.close(() => {
						resolve(true);
					});
				} catch (e) {
					reject('' + e);
				}
			});
		}
		,
		waitForReload () {
			return new Promise((resolve, reject) => {
				try {
					sdkTab.once('ready', () => {
						resolve(true);
					});
				} catch (e) {
					reject('' + e);
				}
			});
		}
		,
		reload () {
			return new Promise((resolve, reject) => {
				try {
					const promise = this.waitForReload();
					sdkTab.reload();
					
					promise.then(() => {
						resolve(true);
					})
					.catch(e => {
						resolve('' + e);
					})
				} catch (e) {
					reject('' + e);
				}
			});
		}
		,
		runContentScript (callback, args) {
			return new Promise((resolve, reject) => {
				try {
					const modContentScript = _modContentScript;
					
					// Securely composed script
					const script = modContentScript.buildScript(callback, args);
					
					
					/*
						contentScriptFile is not usable in this case...
					*/
					const worker = sdkTab.attach({
						contentScript: script // unavoidable
						, onError: (e) => {
							reject(e + '')
						}
					});
					
					
					/*
						The result of the 'callback' (may be `undefined`)
					*/
					worker.port.once('scriptReturn', (result) => {
						resolve(result);
					});
					
					/*
						The exception thrown from the 'callback'
					*/
					worker.port.once('scriptError', (e) => {
						reject(new Error(e + ''));
					});
				} catch (e) {
					reject('' + e);
				}
			});
		}
		,
		_addCloseHandler (handler) {
			if ('function' != typeof handler) {
				throw new TypeError('Not a function');
			}
			
			closeHandlers.add(handler);
		}
		,
		_removeCloseHandler (handler) {
			closeHandlers.delete(handler);
		}
		,
		get isPrivate () {
			return !!_sdkIsPrivate(sdkTab);
		}
		,
		get uri () {
			return sdkTab.url + '';
		}
		,
		set uri (value) {
			const modURI = _modURI;
			sdkTab.url = modURI.resolve(sdkTab.url, value + '');
			return true;
		}
		,
		get _isClosed () {
			return !!closed;
		}
	};
	
	return wrapper;
};


/* Exports */
exports.createSDKTabWrapper = createSDKTabWrapper;


// vim: ts=4 noet ai

